using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using Live2D.Cubism.Core;
using Live2D.Cubism.Rendering;
using UnityEditor;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class Live2DManager : Singleton<Live2DManager>
    {
        private Live2DManager()
        {
        }

        private bool _initialized;
        private int _mapID = 1;
        private Dictionary<int, Live2D> _live2DMap = new Dictionary<int, Live2D>();


        public int Create(string name, Transform parent, string layerName, int orderLayer)
        {
            if (!this._initialized)
            {
                this.Initialize();
            }
            Live2D rLive2D = ClassPool.Get<Live2D>();
            rLive2D.id = this._mapID++;
            this._live2DMap.TryAdd(rLive2D.id, rLive2D);
            this.Load(name, rLive2D, parent, layerName, orderLayer).Forget();
            return rLive2D.id;
        }

        public async UniTask<int> CreateAsync(string name, Transform parent, string layerName, int orderLayer)
        {
            if (!this._initialized)
            {
                this.Initialize();
            }
            Live2D rLive2D = ClassPool.Get<Live2D>();
            rLive2D.id = this._mapID++;
            this._live2DMap.TryAdd(rLive2D.id, rLive2D);
            await this.Load(name, rLive2D, parent, layerName, orderLayer);
            return rLive2D.id;
        }

        private async UniTask Load(string name, Live2D live2D, Transform parent, string layerName, int orderLayer)
        {
            await live2D.Load(name, parent, layerName, orderLayer);
            if (!this._live2DMap.ContainsKey(live2D.id))
            {
                live2D.Free();
            }
        }
        
        public void Remove(int nID)
        {
            if (this._live2DMap.TryGetValue(nID, out Live2D live2D))
            {
                this._live2DMap.Remove(nID);
                if (live2D.loaded)
                {
                    live2D.Free();
                }
            }
        }

        public Live2D Get(int id)
        {
            if (this._initialized && this._live2DMap.TryGetValue(id, out var rLive2D))
            {
                return rLive2D;
            }
            return null;
        }

        public void Initialize()
        {
            if (!this._initialized)
            {
#if UNITY_EDITOR
                if (!StoryClientUtil.IsEditorMode)
#endif
                {
                    ManagerCenter.Entity.EnableGroup((int)EntityPoolGroupType.Live2DEntity);
                }
                this._initialized = true;
            }
        }

        public void Dispose()
        {
            if (this._initialized)
            {
                this._live2DMap.Clear();
#if UNITY_EDITOR
                if (!StoryClientUtil.IsEditorMode)
#endif
                {
                    ManagerCenter.Entity.DisableGroup((int)EntityPoolGroupType.Live2DEntity);
                }
                this._initialized = false;
            }
        }
    }

    public class Live2D : IReusableClassWithFree
    {
        public int id;
        public bool loaded;
        public Live2DEntity entity;
        public GameObject gameObject;
        public Animator animator;

        private CubismRenderController _render;
        public CubismRenderController render
        {
            get => this._render;
            private set
            {
                this._render = value;
                this._render.OverwriteFlagForModelMultiplyColors = true;
            }
        }

        public uint MaxStore => 5;

        public async UniTask Load(string name, Transform parent, string layerName, int orderLayer)
        {
#if UNITY_EDITOR
            if (StoryClientUtil.IsEditorMode)
            {
                var rPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/" + PathConstant.GetLive2DPath(name));
                if (rPrefab)
                {
                    this.gameObject = BattleClientUtil.CreateGameobject(rPrefab);
                    this.render = this.gameObject.GetComponent<CubismRenderController>();
                }
                else
                {
                    LogGame.LogError($"未找到[{name}]的live2d预设");
                }
            }
            else
#endif
            {
                this.entity = ManagerCenter.Entity.Get(PathConstant.GetLive2DPath(name), (int)EntityPoolGroupType.Live2DEntity) as Live2DEntity;
                await this.entity.Load(); 
                this.gameObject = this.entity.gameObject;
                this.render = this.entity.render;
            }
            this.loaded = true;
            this.animator = this.gameObject.GetComponent<Animator>();
            if (parent)
            {
                this.gameObject.transform.SetParent(parent);
            }
            this.gameObject.transform.localScale = Vector3.one;
            this.gameObject.transform.localPosition = Vector3.zero;
            var rRenderController = this.gameObject.GetComponent<CubismRenderController>();
            rRenderController.SortingMode = CubismSortingMode.BackToFrontZ;
            rRenderController.SortingLayer = layerName;
            rRenderController.SortingOrder = orderLayer;
        }
        
        public void OnReset()
        {
            this.entity = null;
            this._render = null;
            this.gameObject = null;
            this.animator = null;
            this.loaded = false;
            this.id = 0;
        }

        public void Free()
        {
            if (this.entity != null)
            {
                this.entity.EntityGroup?.HideEntity(this.entity);
            }
#if UNITY_EDITOR
            if (StoryClientUtil.IsEditorMode)
            {
                BattleClientUtil.SafeDestroy(this.gameObject);
            }
#endif
            ClassPool.Put(this);
        }
    }

    public class Live2DEntity : Entity
    {
        public CubismRenderController render;

        public override void OnLoadComplete()
        {
            this.render = this.gameObject.GetComponent<CubismRenderController>();
        }

        public override void OnPutBackToPool()
        {
            base.OnPutBackToPool();
            this.render = null;
        }
    }
}